package banner

import (
	"context"
	"fmt"
	"strconv"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	"mall/service/backend/model"
	"mall/service/backend/rpc/internal/svc"
	"mall/service/backend/rpc/internal/utils/errorhandler"
	"mall/service/backend/rpc/types/backend"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetBannerByIdLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewGetBannerByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetBannerByIdLogic {
	return &GetBannerByIdLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *GetBannerByIdLogic) GetBannerById(in *backend.BaseIdReq) (*backend.BannerInfo, error) {
	logrus.Info(fmt.Sprintf("GetBannerById BaseIdReq: %+v", in))
	//

	if (in.Filter == nil || len(*in.Filter) == 0) && (in.Id == nil || *in.Id == 0) {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	preloadMap, eagerLoadMap := modelx.ParsePreloadAndEagerLoad(in.Preload, in.EagerLoad)
	// logrus.Info(fmt.Sprintf("GetBannerById preloadMap: %+v", preloadMap))
	//
	// logrus.Info(fmt.Sprintf("GetBannerById eagerLoadMap: %+v", eagerLoadMap))
	//

	resp := &backend.BannerInfo{}

	bannerEntityName := model.RpcEntityNames.Banner
	if _, ok := model.RpcEntityPreloadMap[bannerEntityName]; !ok {
		return resp, nil
	}

	bannerRepositoryName := model.RepositoryNames.Banner
	columnMap, ok := model.RepositoryPreloadMap[bannerRepositoryName]
	if !ok {
		return resp, nil
	}

	var banner *model.Banner
	var bannerId uint64
	if in.Id != nil && *in.Id > 0 {
		data, err := l.svcCtx.Banner.FindOne(l.ctx, *in.Id)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		banner = data
		bannerId = data.ID
	} else {
		var selectCols []string
		if preloadFields, ok := preloadMap[bannerEntityName]; ok {
			selectCols = modelx.ParseSelectColumns(preloadFields, columnMap)
		}

		filterMap := modelx.ParseFilter(in.Filter, columnMap)
		logrus.Info(fmt.Sprintf("GetBannerById filterMap: %+v", filterMap))
		//
		if filterMap == nil {
			return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
		}

		orderBy := modelx.ParseSorter(in.Sorter, columnMap)
		logrus.Info(fmt.Sprintf("GetBannerById orderBy: %s", orderBy))
		//

		if len(orderBy) == 0 {
			orderBy = model.BannerColumns.ID
		}

		res, _, err := l.svcCtx.Banner.GetList(l.ctx, model.M{
			"pageSize": uint64(1),
			"orderBy":  orderBy,
			"select":   strings.Join(selectCols, ","),
		}, -1, filterMap)
		if err != nil {
			return nil, err
		}

		if len(res) == 0 {
			return resp, nil
		}

		banner = res[0]
		bannerId = banner.ID
	}

	if banner == nil {
		return resp, nil
	}

	if banner.Status != uint8(globalkey.StatusEnabled) {
		return resp, nil
	}

	now := time.Now()
	if banner.StartedAt.Valid && banner.StartedAt.Time.After(now) {
		return resp, nil
	}

	if banner.EndedAt.Valid && banner.EndedAt.Time.Before(now) {
		return resp, nil
	}

	var media []*backend.MediaInfo
	subEntitySettingMap := make(map[string]map[string]*model.ColumnSetting)
	if eagerLoadEntities, ok := eagerLoadMap[bannerEntityName]; ok {
		for _, entity := range eagerLoadEntities {
			if entitySettingMap, ok := model.RpcEntityPreloadMap[entity]; ok {
				subEntitySettingMap[entity] = entitySettingMap
			}
		}
	}

	backendMediaEntityName := model.RpcEntityNames.BackendMedia
	backendMediaRepositoryName := model.RepositoryNames.BackendMedia
	if _, ok := subEntitySettingMap[backendMediaEntityName]; ok {
		subPreloadFields, hasSubPreloadFields := preloadMap[backendMediaEntityName]
		subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[backendMediaRepositoryName]
		if hasSubPreloadFields && hasSubColumnMap {
			var subSelectCols []string = modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

			subFilterMap := make(map[string]map[string][]any)
			subFilterMap[model.AttachmentRelationshipColumns.ObjectID] = map[string][]any{
				"equalTo": {bannerId},
			}
			subFilterMap[model.AttachmentRelationshipColumns.ObjectType] = map[string][]any{
				"equalTo": {globalkey.AttachmentLogTypeBanner},
			}
			orderBy := model.AttachmentRelationshipColumns.AttachmentThumbnail + " DESC," +
				model.AttachmentRelationshipColumns.AttachmentOrder
			list, _, err := l.svcCtx.Banner.GetMedia(l.ctx, model.M{
				"orderBy": orderBy,
				"select":  strings.Join(subSelectCols, ","),
			}, -1, subFilterMap)
			if err != nil {
				return nil, err
			}

			if len(list) > 0 {
				for _, v := range list {
					media = append(media, &backend.MediaInfo{
						Uid:       pointy.GetPointer(v.RelationshipID),
						Id:        pointy.GetPointer(strconv.FormatInt(int64(v.AttachmentID), 10)),
						Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
						Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
						Uri:       pointy.GetPointer(v.AttachmentImageSource),
						Url:       pointy.GetPointer(v.AttachmentImageURL),
						AltText:   pointy.GetPointer(v.AttachmentImageAlt),
						MetaData:  pointy.GetPointer(v.AttachmentImageMeta),
					})
				}
			}
		}
	}

	var sort *uint32
	if banner.Sort != uint16(globalkey.SystemDefaultSort) {
		sort = pointy.GetPointer(uint32(banner.Sort))
	}

	return &backend.BannerInfo{
		Id:        pointy.GetPointer(banner.ID),
		PicUrl:    pointy.GetPointer(banner.PicURL),
		Type:      pointy.GetPointer(uint32(banner.Type)),
		Title:     pointy.GetPointer(banner.Title),
		LinkType:  pointy.GetPointer(uint32(banner.LinkType)),
		LinkUrl:   pointy.GetPointer(banner.LinkURL),
		AdType:    pointy.GetPointer(uint32(banner.ObjectType)),
		AdId:      pointy.GetPointer(banner.ObjectID),
		Status:    pointy.GetPointer(uint32(banner.Status)),
		Sort:      sort,
		CreatedAt: pointy.GetPointer(modelx.FormatTime(banner.CreatedAt, "")),
		UpdatedAt: pointy.GetPointer(modelx.FormatTime(banner.UpdatedAt, "")),
		DeletedAt: pointy.GetPointer(modelx.FormatNullDotTime(banner.DeletedAt, "")),
		Media:     media,
	}, nil
}
